﻿using BattleServer.Battle;
using PECommon;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BattleServer
{
    /// <summary>
    /// 战斗世界
    /// </summary>
    public class BattleWorldSys : ILogic
    {
        public WorldContainer mWorldContainer;
        private List<WorldContainer> mContainerList = new List<WorldContainer>();
        /// <summary>
        /// 缓存当前WorldID中对应GameWorld
        /// </summary>
        private ConcurrentDictionary<ulong, SWorld> mWorldDic = new ConcurrentDictionary<ulong, SWorld>();
        /// <summary>
        /// 缓存当前World中，所有要创建或者进入的玩家
        /// </summary>
        private ConcurrentDictionary<ulong, List<SUnitRole>> mUnitRolesDic = new();

        /// <summary>
        /// 缓存第一个通过WorldID请求创建GameWorld的玩家操作
        /// </summary>
        private ConcurrentQueue<ulong> mCreateWorlds = new ConcurrentQueue<ulong>();
        private bool mIsCreating = false;
        private int mCacheCount;  //缓存新进入玩家数量，原子级的操作
        public void Awake()
        {
            for (int i = 0; i < DefaultConfig.ContainerCount; i++)
            {
                mWorldContainer = new WorldContainer(i,this);
                mWorldContainer.Awake();
                mContainerList.Add(mWorldContainer);
            }

            this.Log("Awake BattleWorldSys...");

        }

        public void Destory()
        {
            for (int i = 0; i < DefaultConfig.ContainerCount; i++)
            {
                mContainerList[i].Destory();
            }
            
        }

        public void Update()
        {
            while (!mCreateWorlds.IsEmpty)
            {
                while (mCreateWorlds.TryDequeue(out ulong worldID))
                {
                    WorldContainer container = GetFreestContainer(worldID);
                    container.AddGameWorldID(worldID);
                }
            }
           
        }

        /// <summary>
        /// 进入GameWorld
        /// </summary>
        /// <param name="worldID">World对应的ID</param>
        /// <param name="role">需要进入世界的玩家</param>
        public void EnterGameWorld(ulong worldID,SUnitRole role)
        {
            Interlocked.Increment(ref mCacheCount);
            SWorld world = GetGameWorld(worldID);
            if (world != null)
            {
                world.TryEnterGameWorld(role);
            }
            else
            {
                lock (mUnitRolesDic)
                {
                    mUnitRolesDic.AddOrUpdate(worldID,new List<SUnitRole>() { role }, (k, v) =>
                   {
                       v.Add(role);
                       mIsCreating = true;
                       return v;
                   });
                    if (!mIsCreating)
                    {
                        mCreateWorlds.Enqueue(worldID);
                    }

                }

            }

            Interlocked.Decrement(ref mCacheCount);

        }

        /// <summary>
        /// 或者到最空闲的Container容器
        /// </summary>
        /// <returns></returns>
        public WorldContainer GetFreestContainer(ulong worldID)
        {
            return mContainerList[0];
        }

        /// <summary>
        /// 根据WorldID获取到当前游戏世界
        /// </summary>
        /// <param name="worldID"></param>
        /// <returns></returns>
        public SWorld GetGameWorld(ulong worldID)
        {
            if (mWorldDic.TryGetValue(worldID, out SWorld world))
            {
                return world;
            }
            return null;
        }


        public void AddGameWorld(SWorld world)
        {
            if (!mWorldDic.TryAdd(world.WorldID, world))
            {
                this.Error($"Add new world {world.WorldID} failed!");
            }
            while (true)
            {
                if (mCacheCount == 0)
                {
                    if (mUnitRolesDic.TryRemove(world.WorldID, out List<SUnitRole>? roleList))
                    {
                        for (int i = 0; i < roleList.Count; i++)
                        {
                            this.Log($"Cache unitRole:{roleList[i].UID} enter world");
                            world.TryEnterGameWorld(roleList[i]);
                        }
                    }
                    else
                    {
                        this.Error($"UnitRoleList not exist world:{world.WorldID} enterCache");
                    }
                    break;
                }
            }
            
        }

        public void RemoveGameWorld(ulong worldID)
        {
            if (!mWorldDic.TryRemove(worldID, out SWorld? world))
            {
                this.Error($"Remove world:{worldID} failed!");
            }
            
        }
    }
}
